#include "server.hpp"
#include <iostream>
using namespace std;


server::server(int port, const char* address) {
  listen_port = port;
  
  if ((s_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("Couldn't create socket!");
    exit(1);
  }
  
  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(listen_port);
  inet_pton(AF_INET, address, &server_addr.sin_addr);
  
  if (bind(s_sock, (sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
    perror ("Bind to socket failed");
    exit(1);
  }
  
  if (listen(s_sock, 10) == -1) {
    perror ("Couldn't listen");
  }

  epoll_init();
  event_loop();
}


void server::epoll_init() {
  printf ("In: epoll_init\n");
  if ((epoll_fd = epoll_create(MAX_CLIENTS)) == -1) {
    perror ("Epoll creation failed!");
    exit(1);
  }
  
  ev.events = EPOLLIN;
  ev.data.fd = s_sock;
  
  if (epoll_ctl (epoll_fd, EPOLL_CTL_ADD, s_sock, &ev) < 0) {
    perror ("Server sock not added to epoll");
    exit(1);
  }
  client_count = 0;
  printf ("Out: epoll_init\n");
}

void server::add_sock_to_epoll(int sock) {
  printf ("In: add_sock_to_epoll\n");
  if(epoll_ctl (epoll_fd, EPOLL_CTL_ADD, sock, &ev) < 0) {
    perror ("couldn't add socket");
  }
  printf ("Out: add_sock_to_epoll\n");
}

void server::remove_sock(int sock) {
  printf("In: remove_sock\n");
  if(epoll_ctl (epoll_fd, EPOLL_CTL_DEL, sock, &ev) < 0) {
    perror ("couldn't add socket");
  }
  printf("Out: remove_osck\n");
}

void server::event_loop() {
  printf ("In: Event_Loop\n");
  for(;;) {
    res = epoll_wait (epoll_fd, events, MAX_CLIENTS, -1);
    if (res == -1) {
      perror ("Error in epoll_wait");
      exit(1);
    }
    for (int i = 0; i < res; ++i) {
      if (events[i].data.fd == s_sock) {
        printf ("Event received for server socket\n");
         socklen_t addrlen = sizeof(struct sockaddr_in);
         clients[client_count] = accept(s_sock,
                                       (struct sockaddr*) &client_addr,
                                       &addrlen);
         ev.events = EPOLLIN ;
         ev.data.fd = clients[client_count];
         this->add_sock_to_epoll (clients[client_count]);
         ++client_count;
         break;
      } else {
        if (events[i].events & EPOLLHUP) {
          this->remove_sock(events[i].data.fd);
          close(events[i].data.fd);
          break;
        } 
        
        if (events[i].events & EPOLLIN) {
          this->handle_data(events[i].data.fd);
          break;
        }
          
        if (events[i].events & EPOLLOUT) {
          this->send_data(3, "TEST");
          break;
        }
      }
    }
  }
}


void server::handle_data(int sock) {
  char buf[512];
  int i = 0;
  int bytes = 0;
  r_data = "";
  do {
    bytes = recv (sock, buf, 512, 0);
    r_data += buf;
    printf("Receiving data...\n");
  } while (bytes == 512);
  cout << "Data Received: " << r_data << endl;
  this->send_data(sock, "TEST\r\n");
}

void server::send_data(int client, char const* data) {
  send(client, data, strlen(data), 0);
}
